﻿using SqlToMarkdown;
using System.Diagnostics;
using System.Text.RegularExpressions;

class Program
{
    // 预编译正则表达式，提高匹配速度
    static readonly Regex ColumnPattern = new Regex(@"`(\w+)` (\w+\(?\d*\,?\d*\)?)( CHARACTER SET \w+)?( COLLATE \w+)?( NOT NULL| NULL)?(?: AUTO_INCREMENT)?(?: DEFAULT ([\w\'\-\.]*))?(?: COMMENT '([^']*)')?", RegexOptions.Compiled);
    static readonly Regex PrimaryKeyPattern = new Regex(@"PRIMARY KEY \((`[\w]+`(?:, `[\w]+`)*)\)", RegexOptions.Compiled);
    static readonly Regex KeyPattern = new Regex(@"KEY\s+`[\w]+`\s+\(([^)]+)\)", RegexOptions.Compiled);
    static readonly Regex CommentPattern = new Regex(@"COMMENT\s*='([^']*)'", RegexOptions.Compiled);
    static void Main(string[] args)
    {
        // 创建一个计时器，用于计算执行时间
        var st = new Stopwatch();
        try
        {
            var inputFile = "";
            while (true)
            {
                Console.WriteLine("请输入SQL文件的路径：");
                inputFile = Console.ReadLine()!;  // 接收用户输入的输出Markdown文件路径

                // 检查输入路径是否是有效的文件路径
                if (Directory.Exists(inputFile))
                {
                    Console.WriteLine("这是一个文件夹地址,请输入文件地址");
                }
                else if (File.Exists(inputFile))
                {
                    break;
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("输入的路径不是一个有效的文件路径，请重新输入。");
                    Console.WriteLine();
                }
            }
            st.Start();
            // 获取文件的上一级目录
            string parentDirectory = GetParentDirectory(inputFile);
            // 获取文件名
            string fileName = Path.GetFileName(inputFile);
            // 替换后缀名
            fileName = Path.ChangeExtension(fileName, ".md");
            // 输出 Markdown 文件的路径
            string outputFile = Path.Combine(parentDirectory, fileName);
            Console.WriteLine("------开始执行------");
            Console.WriteLine();
            // 处理 SQL 文件，转换为 Markdown 格式
            ProcessSqlFile(inputFile, outputFile);
        }
        catch (Exception ex)
        {
            throw new Exception($"------执行失败:" + ex.Message);
        }
        finally
        {
            // 停止计时器并输出执行时间
            st.Stop();
            Console.WriteLine("------执行成功------");
            Console.WriteLine();
            Console.WriteLine("生成文件于上传文件同地址");
            Console.WriteLine($"耗时：{st.ElapsedMilliseconds}ms");
        }
        Console.WriteLine("按任意键关闭...");
        Console.ReadKey(); // 等待用户按键
    }
    /// <summary>
    /// 处理Sql文件
    /// </summary>
    /// <param name="inputFile"></param>
    /// <param name="outputFile"></param>
    static void ProcessSqlFile(string inputFile, string outputFile)
    {
        // 读取 SQL 文件内容
        string sqlContent = File.ReadAllText(inputFile);

        // 使用正则表达式移除注释和多余的空格
        sqlContent = Regex.Replace(sqlContent, @"(--.*)|(\s+)", match => match.Groups[1].Success ? "" : " ");

        // 将 SQL 内容按照表定义分割
        var tableDefinitions = Regex.Split(sqlContent, @"CREATE TABLE `");

        // 使用 StreamWriter 写入输出文件
        using (StreamWriter outFile = new StreamWriter(outputFile, false))
        {
            foreach (var tableDefinition in tableDefinitions)
            {
                // 跳过空白的表定义
                if (string.IsNullOrWhiteSpace(tableDefinition)) continue;

                // 提取表名
                string tableName = tableDefinition.Substring(0, tableDefinition.IndexOf('`'));
                string createTableStatement = "CREATE TABLE `" + tableDefinition;

                // 提取表注释
                var match = CommentPattern.Match(tableDefinition);
                var tableComment = match.Success ? match.Groups[1].Value : "";

                // 解析表和列，并生成 Markdown 格式的内容
                string markdown = ParseSqlToMarkdown(createTableStatement, tableName, tableComment);
                outFile.WriteLine(markdown + "\n\n");
            }
        }
    }
    /// <summary>
    /// 将Sql解析为Markdown
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="tableName"></param>
    /// <param name="tableComment"></param>
    /// <returns></returns>
    static string ParseSqlToMarkdown(string sql, string tableName, string tableComment)
    {
        var columns = new List<ColumnInfoDto>();
        // 匹配列定义
        var matches = ColumnPattern.Matches(sql);

        // 解析每个列定义并存储在 columns 列表中
        foreach (Match match in matches)
        {
            columns.Add(new ColumnInfoDto
            {
                Name = match.Groups[1].Value,
                Type = match.Groups[2].Value,
                Nullable = match.Groups[5].Value.Contains("NOT NULL") ? "o" : "x",
                KeyType = "",
                Comment = match.Groups[7].Success ? match.Groups[7].Value : ""
            });
        }

        var keyNameList = new List<KeyInfoDto>();
        // 匹配键定义
        var matchesKey = KeyPattern.Matches(sql);
        int j = 0;
        foreach (Match match in matchesKey)
        {
            string columnsKey = match.Groups[1].Value;
            // 提取键中的列名
            string[] columnNames = columnsKey.Replace("`", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            // 将键信息存储在 keyNameList 列表中
            for (int i = 0; i < columnNames.Length; i++)
            {
                keyNameList.Add(new KeyInfoDto
                {
                    Name = columnNames[i],
                    KeyType = columnNames.Length >= 2 ? $"KEY{j}" : "KEY",
                    Index = (i + 1).ToString()
                });
            }
            j++;
        }

        // 匹配主键定义
        var primaryKeyMatch = PrimaryKeyPattern.Match(sql);
        string primaryKey = primaryKeyMatch.Success ? primaryKeyMatch.Groups[1].Value.Replace("`", "") : "";

        // 生成 Markdown 格式的表头
        string markdown = $"### {tableName}  {tableComment}\n\n";
        markdown += "|<div align=\"center\">列名</div> | <div align=\"center\">数据类型</div> | <div align=\"center\">允许NULL</div> |" +
            " <div align=\"center\">键/索引</div> | <div align=\"center\">描述</div>\n";
        markdown += "---- | -------- | -------- | ------- | ----\n";

        // 如果存在主键，将主键标记在对应列上
        if (!string.IsNullOrEmpty(primaryKey) && columns.Exists(q => q.Name == primaryKey))
        {
            columns.FirstOrDefault(q => q.Name == primaryKey)!.KeyType = "PRIMARY";
        }

        // 将其他键的信息标记在对应列上
        foreach (var keyName in keyNameList.GroupBy(q => q.Name))
        {
            if (columns.Exists(q => q.Name == keyName.Key))
            {
                columns.FirstOrDefault(q => q.Name == keyName.Key)!.KeyType = string.Join(",", keyName.Select(q => q.KeyType));
            }
        }

        // 生成每一列的 Markdown 行
        foreach (var col in columns)
        {
            markdown += $" <div align=\"center\">{col.Name}</div> | <div align=\"center\">{col.Type}</div> | <div align=\"center\">{col.Nullable}</div> | <div align=\"center\">{col.KeyType}</div> | <div align=\"center\">{col.Comment}</div>\n";
        }

        return markdown;
    }
    /// <summary>
    /// 获取文件的上一级目录路径
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    static string GetParentDirectory(string filePath)
    {
        // 获取文件的目录路径
        string directoryPath = Path.GetDirectoryName(filePath)!;

        //// 获取上一级目录路径
        //string parentDirectory = Directory.GetParent(directoryPath)!.FullName;

        return directoryPath;
    }
}